package models;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import models.msgs.*;
import models.msgs.Action;
import models.msgs.Number;
import play.Logger;
import play.mvc.*;
import play.libs.*;
import play.libs.F.*;
import scala.concurrent.Await;
import scala.concurrent.duration.Duration;
import akka.actor.*;
import static akka.pattern.Patterns.ask;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ArrayNode;

import static java.util.concurrent.TimeUnit.*;

public class Human extends UntypedActor
{
    public final String name;
    public final ActorRef table;
    public final int number;
    
    protected WebSocket.In<JsonNode>  in;
    protected WebSocket.Out<JsonNode> out;


    public Human(String _name, WebSocket.In<JsonNode> _in,
            WebSocket.Out<JsonNode> _out, ActorRef _table, int _number)
    {
        name = _name;        
        table = _table;
        number = _number;
        in = _in;
        out = _out;
        

        in.onMessage(new Callback<JsonNode>()
        {
            @Override
            public void invoke(JsonNode event)
            {
                try
                {	
                    	String objectType = event.get("name").asText();
                    	if(objectType.equals("action")) {
                    	    String type = event.get("type").asText();
                    	    int value = event.get("specifier").asInt();
                    	    table.tell(new ActionRequest(number,type,value), getSelf());
                    	    //getSelf().tell(new Action(type, value), getSelf());
                    	}
                    	else if (objectType.equals("number")) {
                    	    int nr = event.get("nr").asInt();                
                    	    getSelf().tell(new Number(nr,name), getSelf() ); 
                    	}
                }
                catch (Exception e)
                {
                    Logger.error(event.getClass().toString());
                    //Logger.error("invokeError");
                }
                
            }
        });

        in.onClose(new Callback0()
        {
            @Override
            public void invoke()
            {
                table.tell(new Quit(name, number), getSelf() );
            }
        });
    }

    @Override
    public void preStart()
    {        
        String text = "my Actor is now running!";
    	table.tell(new Info(text, name), getSelf()); 
    }

    @Override
    public void postStop()
    {
        String text = "I've been killed";
    	table.tell(new Info(text, name), getSelf()); 
    }

    @Override
    public void onReceive(Object msg) throws Exception
    {

            if (msg instanceof Number)
            {   
            	int nr = ((Number) msg).getNumber();            	           			
            	String text = "I've got the number " + nr + " from WebSocket and send it to Table";
            	table.tell(new Info(text, name), getSelf()); 
            	table.tell(new Number(nr, name), getSelf());
            }  
            else if (msg instanceof Card)
            {
            	Card card = (Card) msg;    
            	String text = "I've got " + card.getRank() + " " + card.getColor() + " from Table" ;
            	table.tell(new Info(text, name), getSelf());  
            } 
            
            else if (msg instanceof Info)
            {        
            	Info info = (Info) msg;             	
	        ObjectNode event = Json.newObject();
	        event.put("name", info.getName());
	        event.put("message", "[ "+ info.getName()+ " ] : " + info.getText()); 
	        out.write(event);
            }
            else if (msg instanceof Action) {
        	Action action = (Action) msg;
        	table.tell(new Info("My action was ["+ action.getType()+ action.getSpecifier()+"]", name), getSelf());
            }
            else if (msg instanceof MovePermission) {
        	String perm = ((MovePermission)msg).getPossibleMoves();
        	ObjectNode event = Json.newObject();
        	event.put("permission", 1);
        	if (perm.contains("E"))
        	    event.put("exchange",1);
        	if (perm.contains("H"))
        	    event.put("check",1);
        	if (perm.contains("B"))
        	    event.put("bet",1);
        	if (perm.contains("R"))
        	    event.put("raise",1);
        	if (perm.contains("C"))
        	    event.put("call",1);
        	if (perm.contains("F"))
        	    event.put("fold",1);
        	if (perm.contains("A"))
        	    event.put("allin",1);
        	System.out.println(name +": " + perm);
    		out.write(event);
            }
            else if (msg instanceof AfterMoveInfo) {
        	ObjectNode event = Json.newObject();
        	AfterMoveInfo ami = (AfterMoveInfo)msg;
        	if(ami.getName().equals(name)) {
        	    event.put("myCoins", ami.getCoins());
    	            event.put("myBet", ami.getBet());
    	        }
        	else {
        	    event.put("message", "[ Table ] : " + ami.getName()+ " has " + ami.getCoins() + " and bet="  + ami.getBet()); 
    	        }
	        event.put("maxBet", ((AfterMoveInfo)msg).getMaxBet());
	        event.put("stake", ((AfterMoveInfo)msg).getStake());
	        out.write(event);
            }
            else if (msg instanceof CardInfo) {
        	ObjectNode event = Json.newObject();
	        event.put("cards", ((CardInfo)msg).getHandRepresentation());
	        out.write(event);
            }
            else if (msg instanceof CoinsInfo) {
        	CoinsInfo cInfo = (CoinsInfo)msg;
        	if (cInfo.getPlayersName().equals(name)) {
        	    ObjectNode event = Json.newObject();
        	    event.put("myCoins", cInfo.getNewCoins());
        	    out.write(event);
        	}
        	else {
        	    ObjectNode event = Json.newObject();
    	            event.put("name", cInfo.getPlayersName());
    	            event.put("message", "[ Table ] : " + cInfo.getPlayersName() + " has got " + cInfo.getNewCoins() + "coins"); 
    	            out.write(event);
        	}
            }
            else if (msg instanceof WinnerInfo) {
        	ObjectNode event = Json.newObject();
        	WinnerInfo wInf= (WinnerInfo)msg;
        	int n = wInf.getNames().length;
        	event.put("winners", wInf.getWinners()); 
	        event.put("playersNumber", n );
	        for(int i = 0; i < n; i++) {
        	    event.put("name"+(i+1), wInf.getNames()[i]);
        	}
        	for(int i = 0; i < n; i++) {
        	    System.out.println("hand"+(i+1)+wInf.getHandRepresentations()[i]+ "<");
        	    event.put("hand"+(i+1), wInf.getHandRepresentations()[i]);
        	}
	        out.write(event);
            }
            else {
                unhandled(msg);
            }
            
        }  
            
}

